#region Microsoft Public License
/*
 * (c) Copyright Chenjun Wu. http://utablesdk.codeplex.com
 * 
 * This source is subject to the Microsoft Public License (Ms-PL).
 * Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
 * All other rights reserved.
 */
#endregion

using System;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using UTable.Input.MultiTouch;

namespace UTable.Objects.Controls
{

    public class UElementMenuDirectory : UElementMenuItem
    {
        #region Dependency Properties

        // Using a DependencyProperty as the backing store for IsSubmenuOpen.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsSubmenuOpenProperty =
            DependencyProperty.Register("IsSubmenuOpen", typeof(bool), typeof(UElementMenuDirectory), new UIPropertyMetadata(false));

        // Using a DependencyProperty as the backing store for Orientation.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty OrientationProperty =
            DependencyProperty.Register("Orientation", typeof(double), typeof(UElementMenuDirectory), new UIPropertyMetadata(0.0));

        #endregion

        #region Private Methods

        private UElementMenuPanel _panel;

        private int _activeItemIndex = -1;

        #endregion

        #region Constructors

        static UElementMenuDirectory()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(UElementMenuDirectory), new FrameworkPropertyMetadata(typeof(UElementMenuDirectory)));
            UControlImpl.OverrideMetadata(typeof(UElementMenuDirectory));
        }

        public UElementMenuDirectory(): base()
        {
            this.Role = UElementMenuItemRole.Header;
            this.Loaded += new RoutedEventHandler(UElementMenuItem_Loaded);
        }

        void UElementMenuItem_Loaded(object sender, RoutedEventArgs e)
        {
            // find the panel
            ItemsPresenter p = this.GetTemplateChild("PART_ItemsPresenter") as ItemsPresenter;
            _panel = VisualTreeHelper.GetChild(p, 0) as UElementMenuPanel;
            this.Role = _panel.Children.Count == 0 ? UElementMenuItemRole.Item : UElementMenuItemRole.Header;
            this.Info.Children.Add(_panel.Info);
            _panel.Item = this;
            _panel.ArrangeChildren();
            for (int i = 0; i < _panel.Children.Count; i++)
            {
                if (_panel.Children[i] is UElementMenuItem)
                {
                    (_panel.Children[i] as UElementMenuItem).ParentMenuItem = this;
                    (_panel.Children[i] as UElementMenuItem).MenuRoot = this.MenuRoot;
                }
            }
            CloseSubmenu(false);
        }

        #endregion

        #region Private Methods

        protected override void OnNoContact(FingerEventArgs args)
        {
            base.OnNoContact(args);
        }

        protected override void OnNewContact(FingerEventArgs args)
        {
            base.OnNewContact(args);
            // check whether this item is the end item
            if (this.IsSubmenuOpen)
            {
                if (_activeItemIndex >= 0)
                {
                    // hide the submenu of the current sub menu item
                    if ((this._panel.Children[_activeItemIndex] is UElementMenuDirectory))
                        (this._panel.Children[_activeItemIndex] as UElementMenuDirectory).CloseSubmenu(true);

                    // show the submenu of this item
                    this.FullOpenSubmenu(false);
                }
            }
            else
            {
                // hide the other menu items of the parent menu item
                if (this.ParentMenuItem != null)
                {
                    int index = ParentMenuItem.Items.IndexOf(this);
                    ParentMenuItem.PartialOpenSubmenu(index);
                }

                // show the entire menu items of this menu item
                this.FullOpenSubmenu(true);
            }
        }

        internal void FullOpenSubmenu(bool restart)
        {
            // firstly make sure all the sub menu's submenu is closed
            for (int i = 0; i < this._panel.Children.Count; i++ )
            {
                if (_panel.Children[i] is UElementMenuDirectory)
                {
                    (_panel.Children[i] as UElementMenuDirectory).CloseSubmenu(false);
                }
            }

            // show the full sub menu
            this.IsSubmenuOpen = true;
            _panel.Angle = MaxAngle;
            _panel.Orientation = this.Orientation;
            _activeItemIndex = -1;

            BeginStoryboard storyboard = new BeginStoryboard();
            
            for (int i = 0; i < this._panel.Children.Count; i++)
            {
                if (_panel.Children[i] is UElementMenuItem)
                {
                    (_panel.Children[i] as UElementMenuItem).IsActive = true;
                }
            }

            if (restart)
            {
                // animate the radius
                DoubleAnimation animation = new DoubleAnimation(10.0, Radius, new Duration(TimeSpan.FromMilliseconds(500)));
                animation.SpeedRatio = 2;
                _panel.Radius = 10;
                // _panel.BeginAnimation(UElementMenuPanel.RadiusProperty, CreateDoubleAnimation(100, TimeSpan.FromMilliseconds(600)));
                _panel.BeginAnimation(UElementMenuPanel.RadiusProperty, animation);
            }
            if (SubmenuOpened != null)
                SubmenuOpened(this, null);
        }

        private AnimationTimeline CreateDoubleAnimation(double to, TimeSpan duration)
        {
            SplineDoubleKeyFrame endKeyframe = new SplineDoubleKeyFrame();
            endKeyframe.Value = to;
            endKeyframe.KeyTime = KeyTime.FromTimeSpan(duration);

            KeySpline ks = new KeySpline();
            ks.ControlPoint1 = new Point(0, 1);
            ks.ControlPoint2 = new Point(1, 1);
            endKeyframe.KeySpline = ks;

            // Create Animation
            DoubleAnimationUsingKeyFrames animation = new DoubleAnimationUsingKeyFrames();
            animation.KeyFrames.Add(endKeyframe);
            return animation;
        }

        internal void CloseSubmenu(bool animated)
        {
            if (!this.IsSubmenuOpen)
                return;

            // hide the sub menu
            this.IsSubmenuOpen = false;
            _activeItemIndex = -1;

            //  hide all sub menus
            if (this._panel == null || this._panel.Children == null)
                return;
            for (int i = 0; i < this._panel.Children.Count; i++)
            {
                if (_panel.Children[i] is UElementMenuItem)
                {
                    if (!animated)
                        (_panel.Children[i] as UElementMenuItem).Opacity = 0;
                    (_panel.Children[i] as UElementMenuItem).IsActive = false;
                    if (_panel.Children[i] is UElementMenuDirectory)
                        (_panel.Children[i] as UElementMenuDirectory).CloseSubmenu(animated);
                }
            }
            if (this.SubmenuClosed != null && animated)
                SubmenuClosed(this, null);
        }

        internal void PartialOpenSubmenu(int index)
        {
            // just hide other items
            _activeItemIndex = index;
            for (int i=0; i<this._panel.Children.Count; i++)
            {
                if (i != index && _panel.Children[i] is UElementMenuItem)
                {
                    (_panel.Children[i] as UElementMenuItem).IsActive = false;
                }
            }
        }

        #endregion

        #region Properties
        public bool IsSubmenuOpen
        {
            get { return (bool)GetValue(IsSubmenuOpenProperty); }
            set { SetValue(IsSubmenuOpenProperty, value); }
        }

        //
        // Summary:
        //     Gets or sets the value in degrees that controls the direction in which the
        //     menu item opens.
        //
        //      The Right is 0, and Top is 90
        //
        // Remarks:
        //     The Orientation property is a dependency property that is identified by the
        //     UTable.Objects.Controls.ElementMenuItem.OrientationProperty
        //     field.
        public double Orientation
        {
            get { return (double)GetValue(OrientationProperty); }
            set { SetValue(OrientationProperty, value); }
        }


        /// <summary>
        /// The max angle between the first sub menu item and the last sub menu item
        /// The default value is 135
        /// </summary>
        public double MaxAngle
        {
            get { return (double)GetValue(MaxAngleProperty); }
            set { SetValue(MaxAngleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MaxAngle.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MaxAngleProperty =
            DependencyProperty.Register("MaxAngle", typeof(double), typeof(UElementMenuDirectory), new UIPropertyMetadata(135.0));


        /// <summary>
        /// The radius between the sub-menu item and this menu
        /// The default value is 100
        /// </summary>
        public double Radius
        {
            get { return (double)GetValue(RadiusProperty); }
            set { SetValue(RadiusProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Radius.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty RadiusProperty =
            DependencyProperty.Register("Radius", typeof(double), typeof(UElementMenuDirectory), new UIPropertyMetadata(100.0));



        #endregion

        #region Events
        //
        // Summary:
        //     Occurs when a submenu is closed.
        //
        // Remarks:
        //     The SubmenuClosed event is a routed event that is identified by the UTable.Objects.Controls.ElementMenuItem.SubmenuClosedEvent
        //     field.
        public event EventHandler SubmenuClosed;
        //
        // Summary:
        //     Occurs when a submenu is opened.
        //
        // Remarks:
        //     The SubmenuOpened event is a routed event that is identified by the UTable.Objects.Controls.ElementMenuItem.SubmenuOpenedEvent
        //     field.
        public event EventHandler SubmenuOpened;

        #endregion

        #region Methods
        //
        // Summary:
        //     Gets a geometry for a clipping mask.
        //
        // Parameters:
        //   layoutSlotSize:
        //     The size of the part of the element that does visual presentation.
        //
        // Returns:
        //     The clipping geometry.
        //
        // Remarks:
        //     The mask applies if the layout system tries to arrange an element that is
        //     larger than the available display space.
        protected override Geometry GetLayoutClip(Size layoutSlotSize)
        {
            return base.GetLayoutClip(layoutSlotSize);
        }

        //
        // Summary:
        //     Determines whether the candidate container is an UTable.Objects.Controls.ElementMenuItem
        //     object.
        //
        // Parameters:
        //   item:
        //     The object to check.
        //
        // Returns:
        //     true if item is an ElementMenuItem object; otherwise, false.
        protected override bool IsItemItsOwnContainerOverride(object item)
        {
            return base.IsItemItsOwnContainerOverride(item);
        }

        //
        // Summary:
        //     Called when the System.Windows.Controls.ItemsControl.Items property changes.
        //
        // Parameters:
        //   e:
        //     The event arguments.
        protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
        {
            base.OnItemsChanged(e);
        }

        //
        // Summary:
        //     Prepares the specified element to display the specified item.
        //
        // Parameters:
        //   element:
        //     The element that is used to display the specified item.
        //
        //   item:
        //     The specified item.
        protected override void PrepareContainerForItemOverride(System.Windows.DependencyObject element, object item)
        {
            base.PrepareContainerForItemOverride(element, item);
        }

		public void AddItem(string header, string command)
		{
			UElementMenuItem item = new UElementMenuItem();
			item.Header = header;
			item.Command = command;
			this.Items.Add(item);
		}

        #endregion

        #region Override Methods

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            // create line
            line = this.GetTemplateChild("PART_Line") as Path;
            lineSegment = new LineSegment();
            pathFigure = new PathFigure();
            pathFigure.Segments.Add(lineSegment);
            PathFigureCollection figureCollection = new PathFigureCollection();
            figureCollection.Add(pathFigure);
            line.Data = new PathGeometry(figureCollection);
        }

        #endregion
    }
}
